package com.meeting.project.app;

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import javax.imageio.ImageIO;

import com.alibaba.fastjson.JSONArray;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.meeting.common.utils.file.FileUploadUtils;
import com.meeting.common.utils.file.FileUtils;
import com.meeting.framework.aspectj.lang.annotation.Log;
import com.meeting.framework.aspectj.lang.enums.BusinessType;
import com.meeting.framework.config.RuoYiConfig;
import com.meeting.framework.config.ServerConfig;
import com.meeting.framework.web.controller.BaseController;
import com.meeting.framework.web.domain.AjaxResult;
import com.meeting.project.business.meeting.domain.MeetingVO;
import com.meeting.project.business.meeting.service.IMeetingService;
import com.meeting.project.business.record.domain.SeriesData;
import com.meeting.project.business.record.domain.SignInRecord;
import com.meeting.project.business.record.service.ISignInRecordService;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

/**
 * 人员签到信息Controller
 *
 * @author llmaoa
 * @date 2025-08-04
 */
@Controller
@RequestMapping("/app/record")
public class SignInRecordAppController extends BaseController {
    private String prefix = "app";

    @Autowired
    private ISignInRecordService signInRecordService;

    @Autowired
    private IMeetingService meetingService;

    @Autowired
    private ServerConfig serverConfig;

    private static final Integer QR_CODE_SIZE = 300;
    private static final String QR_CODE_CONTENT_URL = "/app/record/sign/%s/%s";
    private static final Long QR_SCAN_TIME_OUT = 10 * 1000L;

    private static final Map<Integer, String> LEAVE_TYPE_MAP = new HashMap<Integer, String>() {{
        //0=门诊,1=手术,2=会议,3=因公学习,4=外事,5=医联体,6=年休,7=病假,8=其他
        put(0, "门诊");
        put(1, "手术");
        put(2, "会议");
        put(3, "因公学习");
        put(4, "外事");
        put(5, "医联体");
        put(6, "年休");
        put(7, "病假");
        put(8, "其他");
    }};

    /**
     * 获取二维码
     *
     * @param meetingId
     * @param mmap
     * @return
     */
    @GetMapping("qrcode/{meetingId}")
    public String qrcode(@PathVariable("meetingId") Long meetingId, ModelMap mmap) {
        mmap.put("meetingId", meetingId);
        return prefix + "/qrcode";
    }

    /**
     * 获取二维码
     *
     * @param meetingId
     * @return
     */
    @GetMapping("qrcode/img/{meetingId}")
    public ResponseEntity<byte[]> qrcode(@PathVariable("meetingId") Long meetingId) {
        try {
            // 设置二维码参数
            Map<EncodeHintType, Object> hints = new HashMap<>();
            // 字符集编码
            hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
            // 纠错等级
            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
            // 边距
            hints.put(EncodeHintType.MARGIN, 1);

            // 生成二维码矩阵
            long timestamp = System.currentTimeMillis();
            QRCodeWriter qrCodeWriter = new QRCodeWriter();
            String url = serverConfig.getUrl() + String.format(QR_CODE_CONTENT_URL, meetingId, timestamp);
            BitMatrix bitMatrix = qrCodeWriter.encode(url, BarcodeFormat.QR_CODE, QR_CODE_SIZE, QR_CODE_SIZE, hints);

            // 将矩阵转换为 BufferedImage
            BufferedImage bufferedImage = MatrixToImageWriter.toBufferedImage(bitMatrix);

            // 将 BufferedImage 转换为字节数组
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            ImageIO.write(bufferedImage, "PNG", outputStream);

            // 设置响应头
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.IMAGE_PNG);

            // 返回图片字节数组
            return new ResponseEntity<>(outputStream.toByteArray(), headers, HttpStatus.OK);
        } catch (WriterException | IOException e) {
            e.printStackTrace();
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * 签到
     *
     * @param meetingId
     * @param timestamp
     * @param mmap
     * @return
     */
    @GetMapping("sign/{meetingId}/{timestamp}")
    public String sign(@PathVariable("meetingId") Long meetingId, @PathVariable("timestamp") Long timestamp, ModelMap mmap) {
        long now = System.currentTimeMillis();
        if (timestamp == 0L) {
            mmap.put("meetingId", meetingId);
            return prefix + "/signIn";
        }
        // 超时10秒
        if (now - timestamp > QR_SCAN_TIME_OUT) {
            return prefix + "/timeout";
        } else {
            mmap.put("meetingId", meetingId);
            return prefix + "/signIn";
        }
    }

    /**
     * 新增保存人员签到信息
     */
    @Log(title = "人员签到信息", businessType = BusinessType.INSERT)
    @PostMapping("/add")
    @ResponseBody
    public AjaxResult addSave(SignInRecord busiSignInRecord) {
        return toAjax(signInRecordService.insertSignInRecord(busiSignInRecord));
    }

    /**
     * 统计
     *
     * @param meetingId
     * @param mmap
     * @return
     */
    @GetMapping("statistics/{meetingId}")
    public String statistics(@PathVariable("meetingId") Long meetingId, ModelMap mmap) {
        mmap.put("meetingId", meetingId);
        // 会议信息
        MeetingVO meetingVO = meetingService.getMeetingVOById(meetingId);
        meetingVO.setAbsentPeople(meetingVO.getMeetingPeople() - meetingVO.getSignPeople());
        mmap.put("meeting", meetingVO);

        List<SeriesData> leaveList = signInRecordService.statisticsAllByLeaveType();
        List<SeriesData> leaveListData = new ArrayList<>();
        LEAVE_TYPE_MAP.forEach((key, value)-> {
            SeriesData seriesData = leaveList.stream().filter(item -> item.getType().equals(key)).findFirst().orElse(null);
            if (Objects.isNull(seriesData)) {
                leaveListData.add(new SeriesData(NumberUtils.INTEGER_ZERO, value));
            } else {
                seriesData.setName(value);
                leaveListData.add(seriesData);
            }
        });
        mmap.put("leaveList", leaveListData);
        // 参会人员信息
//        SignInRecord signInRecord = new SignInRecord();
//        signInRecord.setMeetingId(meetingId);
//        mmap.put("signInRecordList", signInRecordService.selectSignInRecordList(signInRecord));
        // 获取数据请假分类数据
        List<SeriesData> seriesDatas = signInRecordService.statisticsByLeaveType(meetingId);
        // 对数据进行处理
        List<SeriesData> seriesDataList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(seriesDatas)) {
            List<SeriesData> finalSeriesDataList = seriesDataList;
            LEAVE_TYPE_MAP.forEach((key, value) -> {
                SeriesData seriesData = seriesDatas.stream().filter(item -> item.getType().equals(key)).findFirst().orElse(null);
                if (Objects.isNull(seriesData)) {
                    seriesData = new SeriesData();
                    seriesData.setName(value);
                    seriesData.setValue(0);
                } else {
                    seriesData.setName(value);
                }
                finalSeriesDataList.add(seriesData);
            });
        } else {
            seriesDataList = LEAVE_TYPE_MAP.values().stream().map(s -> {
                SeriesData data = new SeriesData();
                data.setName(s);
                data.setValue(0);
                return data;
            }).collect(Collectors.toList());
        }
        mmap.put("seriesData", JSONArray.toJSONString(seriesDataList));

        // 缺席请假分类统计
        return prefix + "/statistics";
    }


    /**
     * 统计
     *
     * @param meetingId
     * @return
     */
    @PostMapping("series/{meetingId}")
    @ResponseBody
    public AjaxResult statistics(@PathVariable("meetingId") Long meetingId) {
        // 获取数据请假分类数据
        List<SeriesData> seriesDatas = signInRecordService.statisticsByLeaveType(meetingId);
        // 对数据进行处理
        List<SeriesData> seriesDataList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(seriesDatas)) {
            List<SeriesData> finalSeriesDataList = seriesDataList;
            LEAVE_TYPE_MAP.forEach((key, value) -> {
                SeriesData seriesData = seriesDatas.stream().filter(item -> item.getType().equals(key)).findFirst().orElse(null);
                if (Objects.isNull(seriesData)) {
                    seriesData = new SeriesData();
                    seriesData.setName(value);
                    seriesData.setValue(0);
                } else {
                    seriesData.setName(value);
                }
                finalSeriesDataList.add(seriesData);
            });
        } else {
            seriesDataList = LEAVE_TYPE_MAP.values().stream().map(s -> {
                SeriesData data = new SeriesData();
                data.setName(s);
                data.setValue(0);
                return data;
            }).collect(Collectors.toList());
        }
        System.out.println(JSONArray.toJSONString(seriesDataList));
        return AjaxResult.success(seriesDataList);
    }


    /**
     * 通用上传请求（单个）
     */
    @PostMapping("/upload")
    @ResponseBody
    public AjaxResult uploadFile(MultipartFile file) {
        try {
            // 上传文件路径
            String filePath = RuoYiConfig.getUploadPath();
            // 上传并返回新文件名称
            String fileName = FileUploadUtils.upload(filePath, file);
            String url = serverConfig.getUrl() + fileName;
            AjaxResult ajax = AjaxResult.success();
            ajax.put("url", url);
            ajax.put("fileName", fileName);
            ajax.put("newFileName", FileUtils.getName(fileName));
            ajax.put("originalFilename", file.getOriginalFilename());
            return ajax;
        } catch (Exception e) {
            return AjaxResult.error(e.getMessage());
        }
    }
}
